package com.study.concurrentprogramming.aqs;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @Description :
 * @Author : guxuemin
 * @Version : V1.0.0
 * @Date : 2022/5/15 17:52
 */
public class CLH {

    private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new);

    private final AtomicReference<Node> tail = new AtomicReference<>(new Node());

    private static class Node {
        private boolean locked;
    }

    public void lock() throws InterruptedException {
        Node node = this.node.get();
        node.locked = true;
        Node pre = tail.getAndSet(node);
        while (pre.locked) {
            TimeUnit.MICROSECONDS.sleep(1);
        }
    }

    public void unLock() {
        Node node = this.node.get();
        node.locked = false;
        this.node.set(new Node());
    }

    public static void main(String[] args) {
        CLH spinLock = new CLH();
        new Thread(() -> {
            try {
                spinLock.lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("release lock");
            spinLock.unLock();
        }, "t1").start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2 take lock");
            try {
                spinLock.lock();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2 release lock");
            spinLock.unLock();
        },"t2").start();
    }


}
